﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace CSharp.Basic.Learn.EventBus
{
  /// <summary>
  /// Event bus.
  /// 事件总线采用单例模式
  /// 订阅者注册分为自动注册和手动注册两种
  /// 自动注册通过反射查找继承了IEventData和IEventHandler`的类
  /// refs: https://github.com/aspnetboilerplate/aspnetboilerplate/tree/dev/src/Abp/Events/Bus
  /// </summary>
  public class EventBus
  {
    //采用IoC替换反射
    readonly IWindsorContainer _windsorContainer;

    public static EventBus Default { get; } = new EventBus();

    /// <summary>
    /// 线程安全集合 
    /// 用于存放事件类型和对应的事件处理的方法映射字典
    /// Type EventData
    /// List Type EventHandler
    /// </summary>
    private readonly ConcurrentDictionary<Type, List<Type>> _eventAndHandlerMapping;

    public EventBus()
    {
      //初始 IoC 容器
      _windsorContainer = new WindsorContainer();
      _eventAndHandlerMapping = new ConcurrentDictionary<Type, List<Type>>();
      //MapEventToHandler();
    }

    #region methods
    /// <summary>
    /// 手动绑定事件源与事件处理
    /// </summary>
    /// <typeparam name="TEventData"></typeparam>
    /// <param name="eventHandler"></param>
    public void Register<TEventData>(Type eventHandler)
    {
      List<Type> handlerTypes = _eventAndHandlerMapping[typeof(TEventData)];
      if (!handlerTypes.Contains(eventHandler))
      {
        handlerTypes.Add(eventHandler);
        _eventAndHandlerMapping[typeof(TEventData)] = handlerTypes;
      }
    }

    /// <summary>
    /// 手动解除事件源与事件处理的绑定
    /// </summary>
    /// <typeparam name="TEventData"></typeparam>
    /// <param name="eventHandler"></param>
    public void UnRegister<TEventData>(Type eventHandler)
    {
      List<Type> handlerTypes = _eventAndHandlerMapping[typeof(TEventData)];
      if (handlerTypes.Contains(eventHandler))
      {
        handlerTypes.Remove(eventHandler);
        _eventAndHandlerMapping[typeof(TEventData)] = handlerTypes;
      }
    }
    /// <summary>
    /// 注册事件
    /// </summary>
    /// <param name="eventHandler">Event handler.</param>
    /// <typeparam name="TEventData">The 1st type parameter.</typeparam>
    public void Register<TEventData>(IEventHandler<TEventData> eventHandler)
      where TEventData : IEventData
    {
      // TODO 这里的参数应该是类型还是实例？
      //var handlerTypes = _eventAndHandlerMapping[typeof(TEventData)];
      //if (!handlerTypes.Contains(eventHandler))
      //{
      //  handlerTypes.Add(eventHandler);
      //  _eventAndHandlerMapping[typeof(TEventData)] = handlerTypes;
      //}
    }

    /// <summary>
    /// 手动注册事件及对应的事件处理方法
    /// </summary>
    /// <param name="eventType">Event type.</param>
    /// <param name="eventHandler">Event handler.</param>
    public void Register(Type eventType, Type eventHandler)
    {
      //注册IEventHandler<T>到IOC容器
      var handlerInterface = eventHandler.GetInterface("IEventHandler`1");
      if (!_windsorContainer.Kernel.HasComponent(handlerInterface))
      {
        _windsorContainer.Register(Component.For(handlerInterface, eventHandler));
      }
      // 注册到事件总线字典
      if (_eventAndHandlerMapping.ContainsKey(eventType))
      {
        List<Type> handlerTypes = _eventAndHandlerMapping[eventType];
        if (!handlerTypes.Contains(eventHandler))
        {
          handlerTypes.Add(eventHandler);
          _eventAndHandlerMapping[eventType] = handlerTypes;
        }
      }
      else
      {
        List<Type> handlerTypes = new List<Type>
        {
          eventHandler
        };
        _eventAndHandlerMapping[eventType] = handlerTypes;
      }
    }

    /// <summary>
    /// 发布事件
    /// 根据事件类型找到对应的事件处理集合然后触发集合中所有处理方法
    /// </summary>
    public void Publish<TEventData>(TEventData eventData) where TEventData : IEventData
    {
      // 1.从映射字典中找到TEventData对应的事件处理集合
      var handlerTypes = _eventAndHandlerMapping[typeof(TEventData)];

      // 2.不使用反射创建事件处理的实例而是从IoC容器中解析服务
      foreach (var handlerType in handlerTypes)
      {
        var handlerInterface = handlerType.GetInterface("IEventHandler`1");
        var eventHandlers = _windsorContainer.ResolveAll(handlerInterface);
        foreach (var eventHandler in eventHandlers)
        {
          // 3.调用事件处理方法
          var item = eventHandler as IEventHandler<TEventData>;
          item?.Handle(eventData);
        }
      }
    }

    /// <summary>
    ///通过反射，将事件源与事件处理绑定
    /// </summary>
    private void MapEventToHandler()
    {
      Assembly assembly = Assembly.GetExecutingAssembly();
      foreach (var type in assembly.GetTypes())
      {
        if (typeof(IEventHandler).IsAssignableFrom(type))//判断当前类型是否实现了IEventHandler接口
        {
          Type handlerInterface = type.GetInterface("IEventHandler`1");//获取该类实现的泛型接口
          if (handlerInterface != null)
          {
            Type eventDataType = handlerInterface.GetGenericArguments()[0]; // 获取泛型接口指定的参数类型

            if (_eventAndHandlerMapping.ContainsKey(eventDataType))
            {
              List<Type> handlerTypes = _eventAndHandlerMapping[eventDataType];
              handlerTypes.Add(type);
              _eventAndHandlerMapping[eventDataType] = handlerTypes;
            }
            else
            {
              var handlerTypes = new List<Type> { type };
              _eventAndHandlerMapping[eventDataType] = handlerTypes;
            }
          }
        }
      }
    }

    public void IoCMapEventToHandler()
    {
      var assembly = Assembly.GetExecutingAssembly();
      // 1.注册所有IEventHandler<>到容器中
      _windsorContainer.Register(Classes.FromAssembly(assembly)
      .BasedOn(typeof(IEventHandler<>))
      .WithService
      .AllInterfaces()
      // TODO:为什么事件处理类需要注册为单例
      .LifestyleSingleton());
      // 2.映射事件类型和事件处理
      //2.从IOC容器中获取注册的所有IEventHandler
      var handlers = _windsorContainer.Kernel.GetHandlers(typeof(IEventHandler));
      foreach (var handler in handlers)
      {
        //循环遍历所有的IEventHandler<T>
        var interfaces = handler.ComponentModel.Implementation.GetInterfaces();
        foreach (var @interface in interfaces)
        {
          if (!typeof(IEventHandler).IsAssignableFrom(@interface))
          {
            continue;
          }

          //获取泛型参数类型
          var genericArgs = @interface.GetGenericArguments();
          if (genericArgs.Length == 1)
          {
            //注册到事件源与事件处理的映射字典中
            Register(genericArgs[0], handler.ComponentModel.Implementation);
          }
        }
      }
    }
    /// <summary>
    /// 根据事件源触发绑定的事件处理
    /// </summary>
    /// <typeparam name="TEventData"></typeparam>
    /// <param name="eventData"></param>
    public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
    {
      List<Type> handlers = _eventAndHandlerMapping[eventData.GetType()];

      if (handlers != null && handlers.Count > 0)
      {
        foreach (var handler in handlers)
        {
          MethodInfo methodInfo = handler.GetMethod("Handle");
          if (methodInfo != null)
          {
            object obj = Activator.CreateInstance(handler);
            methodInfo.Invoke(obj, new object[] { eventData });
          }
        }
      }
    }

    #endregion
  }
}
